﻿using System;
using System.Collections.Generic;
using System.Linq;
using CrmClient.QueryConvert;
using Microsoft.Xrm.Sdk.Query;

namespace CrmClient.Query
{
    public class CrmJoinedQueryable<T> : CrmQueryable<T>
    {
        private List<CrmLink> _links = new List<CrmLink>();

        internal CrmJoinedQueryable(CrmClientBase queryExecutor, PropertiesMap propertiesMap, string entityName)
            : base(queryExecutor, propertiesMap, entityName)
        { }

        internal void AddLink(CrmLinkAlias alias, string fromCrmAttrName, string toCrmAttrName, IEnumerable<string> toEntityCrmAttrs, JoinOperator joinOperator, FilterExpression filter)
        {
            _links.Add(new CrmLink(alias, EntityName, fromCrmAttrName, toCrmAttrName, toEntityCrmAttrs, joinOperator, filter));
        }

        protected override void SetQueryColumnSet(QueryExpression query)
        {
            query.ColumnSet = new ColumnSet(PropertiesMap.Where(i => i.IsMappedToCrmEntity && !i.CrmAttr.IsAliased).Select(i => i.CrmAttr.ToString()).Distinct().ToArray());
        }

        protected override QueryExpression BuildQuery()
        {
            var query = base.BuildQuery();
            foreach (var link in _links)
                query.LinkEntities.Add(link.CreateLinkEntity());
            return query;
        }

        internal override CrmQueryable<R> CreateInstance<R>(PropertiesMap propertiesMap, string entityName)
        {
            return new CrmJoinedQueryable<R>(QueryExecutor, propertiesMap, entityName);
        }

        internal override CrmJoinedQueryable<R> ConvertToJoin<R>(string toEntityName, Func<CrmLinkAlias, PropertiesMap> propertiesMapGetter, out CrmLinkAlias alias)
        {
            var exists = _links.Where(i => i.Alias.EntityName == toEntityName).ToList();
            var maxNum = 0;
            if (exists.Count > 0)
                maxNum = exists.Max(i => i.Alias.Num);
            alias= new CrmLinkAlias(maxNum + 1, toEntityName);
            var propertiesMap = propertiesMapGetter(alias);
            var res = new CrmJoinedQueryable<R>(QueryExecutor, propertiesMap, toEntityName);
            foreach (var link in _links)
                res._links.Add(link.Clone());
            CloneContent(res);
            return res;
        }
    }
}
